/**
 * Copyright (C) 2017 - 2020 https://github.com/joewee
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bifrost.web.controller;

import com.bifrost.annotation.Authorization;
import com.bifrost.annotation.CurrentUser;
import com.bifrost.common.model.ResultModel;
import com.bifrost.entity.Customer;
import com.bifrost.game.entity.LotteryAward;
import com.bifrost.game.entity.LotteryGame;
import com.bifrost.game.entity.LotteryGameAward;
import com.bifrost.game.entity.LotteryGameWinner;
import com.bifrost.game.exception.LotteryUnavailableException;
import com.bifrost.game.service.LotteryGameService;
import com.bifrost.service.CustomerService;
import com.bifrost.util.DateUtils;
import com.bifrost.util.LocalDateUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 抽奖游戏控制器
 *
 * @author joewee
 * @version 1.0.0
 * @Date 2018/5/9 11:10
 */
@RestController
@RequestMapping("/api/lotteryGame")
public class LotteryGameController {
    @Autowired
    LotteryGameService gameService;
    @Autowired
    RedisTemplate<String, String> redis;
    @Autowired
    CustomerService customerService;
    public static final String KEY_PREFIX = "lotteryGame";

    @GetMapping
    @Authorization
    public ResultModel list(@CurrentUser Long userId) {
        Customer customer = customerService.findCustomer(userId);
        List<LotteryGame> games = gameService.findGamesByMerchant(customer.getMerchantStore().getMerchantId());
        if (CollectionUtils.isNotEmpty(games)) {
            games = games.stream().filter(lotteryGame -> {
                return Boolean.TRUE.equals(lotteryGame.isEnabled()) && lotteryGame.isActive();
            }).collect(Collectors.toList());
            return ResultModel.ok().put("list", games);
        } else {
            return ResultModel.error("未找到相关记录");
        }

    }

    @GetMapping("/{uid}")
    @Authorization
    public ResultModel query(@CurrentUser Long userId, @PathVariable("uid") Long uid) {
        if (uid==null) {
            return ResultModel.error("uid不能为空");
        }
        LotteryGame game = gameService.findById(uid);
        List<LotteryGameAward> gameAwards = game.getLotteryGameAwards();
        int sumTimes = 0;
        int quantiies = 0;
        List<Map> awards = new ArrayList<Map>(gameAwards.size());

        for (LotteryGameAward lotteryGameAward : gameAwards) {
            quantiies += lotteryGameAward.getQuantity();
            sumTimes += lotteryGameAward.getMaxTimes();
            LotteryAward lotteryAward =lotteryGameAward.getLotteryAward();
            Map award = new HashMap();
            award.put("name",lotteryAward.getName());
            award.put("description",lotteryAward.getDescription());
            award.put("imgUrl",lotteryAward.getImgUrl());
            award.put("quantity",lotteryAward.getQuantity());
            awards.add(award);
        }
        //总次数大于总奖品数说明会有不中奖的情况即不是百分之百中奖
        if (sumTimes > quantiies) {
            LotteryGameAward award = new LotteryGameAward();
            award.setGrade("谢谢参与");
            award.setQuantity(sumTimes-quantiies);
            award.setId(0L);
            gameAwards.add(award);
        }

        if (game != null) {
            return ResultModel.ok().put("data", game).put("awards",awards);
        } else {
            return ResultModel.error("未找到相关记录");
        }

    }

    @GetMapping("/draw/{uid}")
    @Authorization
    public ResultModel draw(@CurrentUser Long userId, @PathVariable("uid") Long uid) {
        if (uid==null) {
            return ResultModel.error("uid不能为空");
        }
        LotteryGame game = gameService.findById(uid);
        if (game != null) {
            try {
                // init
                Customer customer = customerService.findCustomer(userId);
                String openId = customer.getOpenId();
                // 离活动结束时间差
                Long activeSeconds = 300L;
                if(LocalDateTime.now().isBefore(LocalDateUtils.dateTimeFromDate(game.getEndTime()))){
                    activeSeconds = Duration.between(LocalDateTime.now(),LocalDateUtils.dateTimeFromDate(game.getEndTime())).getSeconds();
                }

                //参与总次数
                String limitString = redis.boundValueOps(bulidKey("count",openId,uid)).get();
                if(StringUtils.isNotBlank(limitString)){
                    int count = Integer.valueOf(limitString);
                    if(game.getAttendCountLimit()!=null&&game.getAttendCountLimit()>0&&count>=game.getAttendCountLimit()){
                        return ResultModel.error("您参与次数已达上限");
                    }
                }

                //单日参与总次数
               String countString = redis.boundValueOps(bulidKey("nowDay",openId,uid)).get();
               if(StringUtils.isNotBlank(countString)){
                   int count = Integer.valueOf(countString);
                   if(game.getDayAttendLimit()!=null&&game.getDayAttendLimit()>0&&count>=game.getDayAttendLimit()){
                       return ResultModel.error("您今天参与次数已达上限，请明日再来");
                   }
               }

                //设置总次数
                if(StringUtils.isBlank(limitString)){
                    //TODO 设置实效时间
                    redis.boundValueOps(String.format(bulidKey("count",openId,uid))).set("1",activeSeconds,TimeUnit.SECONDS);
                }else{
                    redis.boundValueOps(bulidKey("count",openId,uid)).increment(1);
                }

                //设置单日次数
                if(StringUtils.isBlank(countString)){
                    long seconds = DateUtils.getReaminSecondsToday();
                    redis.boundValueOps(bulidKey("nowDay",openId,uid)).set("1",seconds, TimeUnit.SECONDS);
                }else{
                    redis.boundValueOps(bulidKey("nowDay",openId,uid)).increment(1);
                }

                //每人总共中奖限制
                String winCountLimit = redis.boundValueOps(bulidKey("winCountLimit",openId,uid)).get();
                if(StringUtils.isNotBlank(winCountLimit)){
                    int count = Integer.valueOf(winCountLimit);
                    if(game.getWinCountLimit()!=null&&game.getWinCountLimit()>0&&count>=game.getWinCountLimit()){
                        return ResultModel.ok("未中奖").put("data", null).put("id",0);
                    }
                }

                //每人每日中奖限制
                String dayWinLimit = redis.boundValueOps(bulidKey("dayWinLimit",openId,uid)).get();
                if(StringUtils.isNotBlank(dayWinLimit)){
                    int count = Integer.valueOf(dayWinLimit);
                    if(game.getDayWinLimit()!=null&&game.getDayWinLimit()>0&&count>=game.getDayWinLimit()){
                        return ResultModel.ok("未中奖").put("data", null).put("id",0);
                    }
                }

                LotteryGameWinner winner = gameService.draw(customer.getOpenId(), uid);

                if (winner == null) {
                    return ResultModel.ok("未中奖").put("data", null).put("id",0);
                } else {
                   LotteryAward lotteryAward = winner.getLotteryAward();
                    LotteryGameAward award = gameService.findLotteryGameAward(game,lotteryAward);
                    if(award==null){
                        return ResultModel.ok("未中奖").put("data", null).put("id",0);
                    }

                    // 已中奖 每人总共中奖限制
                    if(StringUtils.isBlank(winCountLimit)) {
                        long seconds = DateUtils.getReaminSecondsToday();
                        redis.boundValueOps(bulidKey("winCountLimit",openId,uid)).set("1",activeSeconds,TimeUnit.SECONDS);
                    }else {
                        int count = Integer.valueOf(winCountLimit);
                        redis.boundValueOps(bulidKey("winCountLimit",openId,uid)).increment(1);
                    }

                    //每人每日中奖限制
                    if(StringUtils.isBlank(dayWinLimit)) {
                        long seconds = DateUtils.getReaminSecondsToday();
                        redis.boundValueOps(bulidKey("dayWinLimit",openId,uid)).set("1",seconds,TimeUnit.SECONDS);
                    }else {
                        int count = Integer.valueOf(dayWinLimit);
                        redis.boundValueOps(bulidKey("dayWinLimit",openId,uid)).increment(1);
                    }

                    return ResultModel.ok("恭喜您中奖").put("data",String.format("%s:%s",award.getGrade(),lotteryAward.getName()) )
                            .put("id",award.getId());
                }
            } catch (LotteryUnavailableException e) {
                return ResultModel.error(e.getErrorMsg());
            }

        } else {
            return ResultModel.error("未找到相关记录");
        }
    }

    protected String bulidKey(String temp , String openId , Long uid ){
        return String.format("%s:%s:%s:%s",KEY_PREFIX,temp,openId,uid);
    };
}
